package  
{
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.geom.Point;
	import org.flixel.*;
	import flash.utils.ByteArray;
	
	/**
	 * ...
	 * @author Euan MacDougall
	 */
	public class PlayState extends FlxState
	{
		public var level:FlxTilemap;
		public var player:FlxSprite;
		
		public var _CCTVCameras:FlxGroup;
		
		public var totalWeight:Number = 0;
		public var totalValue:Number = 0;
		
		public var maxWeight:Number = 100;
		
		public var mPlayerInfo:PlayerInfo;
		
		public var defaultItems:FlxGroup;
		public var collectables:FlxGroup;
		public var selectedItem:Collectable;
		
		public var doors:FlxGroup;
		
		public var weightText:FlxText;
		public var valueText:FlxText;
		
		public var currentLevel:int = 1;
		public var maxLevel:int = 2;
		
		[Embed(source = "Resources/Player1.png")] private var PlayerTexture:Class
		[Embed(source = "Resources/Items.png")] private var ItemsTexture:Class
		[Embed(source = "Resources/TileMap.png")] private var LevelTexture:Class
		[Embed(source = "Resources/MapLayer1.txt", mimeType = "application/octet-stream")] private var LevelMap:Class
		[Embed(source = "Resources/BackgroundTileMap.png")] private var BackgroundTexture:Class
		[Embed(source = "Resources/BackgroundLayer.txt", mimeType = "application/octet-stream")] private var BackgroundMap:Class
		[Embed(source = "Resources/levelsInfo.txt", mimeType = "application/octet-stream")] private var LevelsInfo:Class
		
		public function PlayState(level:int = 1, playerInfo:PlayerInfo = null)
		{
			currentLevel = level;
			if (currentLevel > maxLevel) currentLevel = 1;
			
			if (playerInfo == null)
			{
				playerInfo = new PlayerInfo();
			}
			mPlayerInfo = playerInfo;
			
			maxWeight = mPlayerInfo.maxWeight;
		}
		
		override public function create():void
		{
			FlxG.debug = true;
			
			FlxG.bgColor = 0xff00001a;
			
			//*** Level info ***//
			var back:FlxTilemap = new FlxTilemap();
			var backMapString:Array = (new BackgroundMap() as ByteArray).toString().split("#level#");
			var index:int = currentLevel > backMapString.length ? 0 : currentLevel - 1;
			backMapString[index] = backMapString[index].substr(2);
			back.loadMap(backMapString[index], BackgroundTexture, 16, 16);
			add(back);
			
			level = new FlxTilemap();
			var levelMapString:Array = (new LevelMap() as ByteArray).toString().split("#level#");
			index = currentLevel > levelMapString.length ? 0 : currentLevel - 1;
			levelMapString[index] = levelMapString[index].substr(2);
			level.loadMap(levelMapString[index], LevelTexture, 16, 16);
			add(level);
			
			FlxG.worldBounds.width = level.width;
			FlxG.worldBounds.height = level.height;
			
			//*** Player info ***//
			player = new FlxSprite();
			player.loadGraphic(PlayerTexture, true, true, 18, 28);
			player.addAnimation("run", [0, 2], 5);
			player.addAnimation("idle", [0, 1], 3);
			player.maxVelocity.x = 1.4 * mPlayerInfo.moveSpeedModifier;
			player.maxVelocity.y = 400;
			player.acceleration.y = 500;
			player.drag.x = player.maxVelocity.x * 8;
			
			player.facing = 0;
			
			//*** Item Stuff ***//
			selectedItem = null;
			
			collectables = new FlxGroup();
			defaultItems = new FlxGroup();
			doors = new FlxGroup();
			
			var newItem:Collectable = new Collectable(0, 0);
			newItem.init(ItemsTexture, 0, 15, 30, "Vase");
			defaultItems.add(newItem);
			newItem = new Collectable(0, 0);
			newItem.init(ItemsTexture, 1, 5, 90, "Diamond");
			defaultItems.add(newItem);
			newItem = new Collectable(0, 0);
			newItem.init(ItemsTexture, 2, 25, 70, "Golden Cow");
			defaultItems.add(newItem);
			newItem = new Collectable(0, 0);
			newItem.init(ItemsTexture, 3, 40, 10, "House Tree", 16, 32);
			defaultItems.add(newItem);
			newItem = new Collectable(0, 0);
			newItem.init(ItemsTexture, 4, 80, 30, "Roof Toilet", 16, 16);
			defaultItems.add(newItem);
			newItem = new Collectable(0, 0);
			newItem.init(ItemsTexture, 2, 80, 60, "Big TV", 48, 32);
			defaultItems.add(newItem);
						
			//*** Load level from file ***//
			var lines:Array = (new LevelsInfo() as ByteArray).toString().split('\n');
			
			var levelsFound:int = 0
			for (var i:int = 0; i < lines.length; i++)
			{
				var linei:String = new String();
				for (var c:int = 0; c < lines[i].length - 1; c++)
				{
					if (lines[i].charAt(c) != '\n')
						linei += lines[i].charAt(c);
				}
				if (linei.substr(0, 2) == "//") continue;
				if (linei == "#level#")
				{
					levelsFound++;
					continue;
				}
				if (levelsFound != currentLevel) continue;
				if (linei == "player")
				{
					var thisLine:String = lines[i + 1];
					var comma:int = thisLine.indexOf(",");
					if (comma == -1) continue;
					player.x = int(thisLine.substring(0, comma)) * 16;
					var yPos:int = int(thisLine.substring(comma + 1)) * 16;
					if (yPos < 0) yPos = level.height + yPos;
					player.y = yPos;
					i++;
					continue;
				}
				if (linei == "collectables")
				{
					var checkLine:int = 1;
					while (true)
					{
						var thisLine:String = lines[i + checkLine];
						if (thisLine.substr(0, 2) == "//")
						{
							checkLine++;
							continue;
						}
						else if (thisLine.substring(0, 3) != "col") break;
						
						var comma1:int = thisLine.indexOf(",", 4);
						var comma2:int = thisLine.indexOf(",", comma1 + 1);
						
						addCollectable(int(thisLine.substring(4, comma1)), 
							int(thisLine.substring(comma1 + 1, comma2)),
							int(thisLine.substring(comma2 + 1)));
						
						checkLine++;
						if (i + checkLine >= lines.length) break;
					}
					i = i + checkLine - 1;
				}
				if (linei == "doors")
				{
					var checkLine:int = 1;
					while (true)
					{
						var thisLine:String = lines[i + checkLine];
						if (thisLine.substr(0, 2) == "//")
						{
							checkLine++;
							continue;
						}
						else if (thisLine.substring(0, 3) != "doo") break;
												
						var newDoor1:Door = new Door();
						var newDoor2:Door = new Door();
						if (true)
						{
							var comma1:int = thisLine.indexOf(",", 4);
							var firstVal:int = int(thisLine.substring(4, comma1));
							firstVal *= firstVal < 0 ? -1 : 1;
							var comma2:int = thisLine.indexOf(",", comma1 + 1);
							var secondVal:int = int(thisLine.substring(comma1 + 1, comma2));
							secondVal = secondVal < 0 ? level.height + secondVal : secondVal;
							var comma3:int = thisLine.indexOf(",", comma2 + 1);
							newDoor1.init(new Point(firstVal, secondVal), new Point(int(thisLine.substring(comma2 + 1, comma3)), int(thisLine.substring(comma3 + 1))), newDoor2);
						}
						checkLine++;
						thisLine = lines[i + checkLine];
						if (true)
						{
							var comma1:int = thisLine.indexOf(",", 4);
							var firstVal:int = int(thisLine.substring(4, comma1));
							firstVal *= firstVal < 0 ? -1 : 1;
							var comma2:int = thisLine.indexOf(",", comma1 + 1);
							var secondVal:int = int(thisLine.substring(comma1 + 1, comma2));
							secondVal = secondVal < 0 ? level.height + secondVal : secondVal;
							var comma3:int = thisLine.indexOf(",", comma2 + 1);
							newDoor2.init(new Point(firstVal, secondVal), new Point(int(thisLine.substring(comma2 + 1, comma3)), int(thisLine.substring(comma3 + 1))), newDoor1);
						}
						doors.add(newDoor1);
						doors.add(newDoor2);
						
						checkLine++;
						if (i + checkLine >= lines.length) break;
					}
					i = i + checkLine - 1;
				}
			}
			
			add(doors);
			add(collectables);
			add(player);
			
			//*** HUD ***//
			valueText = new FlxText(20, 20, 200);
			add(valueText);
			weightText = new FlxText(20, valueText.y + valueText.height + 10, 100);
			add(weightText);
			valueText.scrollFactor.x = valueText.scrollFactor.y =
				weightText.scrollFactor.x = weightText.scrollFactor.y = 0;
			updateHUD();
			
			// Camera
			FlxG.camera.setBounds(0, 0, level.width, level.height);
			FlxG.camera.follow(player, FlxCamera.STYLE_PLATFORMER);
			
			//CCTVCamera Test
			_CCTVCameras = new FlxGroup();
			_CCTVCameras.add(new CCTVCamera(380, level.height - 6*16, player));
			add(_CCTVCameras);
		}
		
		public function addCollectable(type:int, x:Number, y:Number)
		{
			var newItem:Collectable = new Collectable(x, y);
			newItem.init(defaultItems.members[type].mGraphic, defaultItems.members[type].mFrame, defaultItems.members[type].mWeight, 
				defaultItems.members[type].mValue, defaultItems.members[type].mName, defaultItems.members[type].mWidth, defaultItems.members[type].mHeight);
			add(newItem.mText);
			collectables.add(newItem);
		}
		
		override public function update():void
		{
			//*** Player movement ***//
			player.acceleration.x = 0;
			var moveSpeed:Number = player.maxVelocity.x * 10;
			if (FlxG.keys.LEFT)
			{
				player.acceleration.x = -moveSpeed;
				player.facing = 1;
			}
			if (FlxG.keys.RIGHT)
			{
				player.acceleration.x = moveSpeed;
				player.facing = 0;
			}
			if((FlxG.keys.SPACE) && player.isTouching(FlxObject.FLOOR))
				player.velocity.y = -player.maxVelocity.y / 2.5;
		 
			if(player.acceleration.x == 0) 
				player.play("idle");
			else
				player.play("run");
				
			super.update();
			
			// Item info display
			if (!FlxG.overlap(player, collectables, viewCollectable))
			{
				if (selectedItem != null)
				{
					selectedItem.mText.kill();
					selectedItem = null;
				}
			}
			// Item collection
			if (FlxG.keys.justPressed("DOWN") && selectedItem != null)
			{
				takeItem(selectedItem);
				updateHUD();
			}
			
			// Go through doors
			if (FlxG.keys.justPressed("UP"))
			{
				FlxG.overlap(player, doors, enterDoorway)
			}
			
			//*** Collision ***//
			FlxG.collide(level, player);
			if (player.y > level.y + level.height)
			{
				FlxG.resetState();
			}
			if(playerEscaping()){}
			//else if (player.x < level.x) player.x = level.x;
			//else if (player.x + player.width > level.x + level.width) player.x = level.x + level.width - player.width;
			// Re-initialise player collision for next frame
			player.solid = true;
			
			updateHUD();
		}
		
		public function viewCollectable(player:FlxSprite, item:Collectable):void
		{
			if(selectedItem == item) return;
			if(selectedItem != null) selectedItem.mText.kill();
			selectedItem = item;
			selectedItem.mText.revive();
		}
		
		public function updateHUD():void
		{
			weightText.text = "Weight: " + totalWeight + " / " + maxWeight;
			valueText.text = "Total value: " + totalValue + "   " + int(player.x) + " " + String(int(player.y + player.height));
		}
		
		public function takeItem(item:Collectable):void
		{
			if (totalWeight + item.mWeight > maxWeight) return;
			item.kill();
			totalValue += item.mValue;
			totalWeight += item.mWeight;
			if (selectedItem == item)
			{
				selectedItem.mText.kill();
				selectedItem = null;
			}
		}
		
		public function enterDoorway(player:FlxSprite, door:Door)
		{
			player.solid = false; // make move through walls
			player.acceleration.x = player.velocity.x = 0;
			var dest:Door = door.dest;
			player.x = dest.x + (dest.width - player.width) / 2;
			player.y = dest.y + dest.height - player.height;
		}
		
		public function playerEscaping():Boolean
		{
			if (player.x <= level.x - 9 * player.width / 10 || player.x + player.width / 10 >= level.x + level.width)
			{
				var stuff:Array = new Array();
				for (var i:int = 0; i < collectables.length; i++)
				{
					if (collectables.members[i].alive) continue;
					var whereItAt:int = stuff.indexOf(collectables.members[i].mName);
					if (whereItAt == -1)
					{
						stuff.push(collectables.members[i].mName);
						stuff.push(1);
					}
					else
					{
						stuff[whereItAt + 1]++;
					}
				}
				FlxG.switchState(new LevelCompeteState(currentLevel, mPlayerInfo, totalValue, stuff));
			}
			return true;
		}
	}

}